﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Entities
{
    public class HostedFile : BaseEntity
    {
        /// <summary>
        /// Полн
        /// </summary>
        public static string StorageDir { get; set; }

        private static int FailConstant = 15;

        private string _original_file_name;
        private string _server_side_file_name;
        private string _short_link_id;
        private long _file_length;
        private bool _shared_mode;
        private int _owner_id;
        private int _downloads_count;


        /// <summary>
        /// Количество раз, сколько был скачан файл
        /// </summary>
        public int DownloadsCount
        {
            // TODO: Include it into DAO's etc.
            get { return _downloads_count; }
            set { _downloads_count = value; }
        }


        /// <summary>
        /// ID владельца файла
        /// </summary>
        public int OwnerID
        {
            get { return _owner_id; }
            set { _owner_id = value; }
        }

        /// <summary>
        /// Флаг общедоступности
        /// </summary>
        public bool Shared
        {
            get
            {
                return _shared_mode;
            }
            set
            {
                this.State = EntityState.Modified;
                _shared_mode = value;
            }
        }

        /// <summary>
        /// Размер размещенного файла
        /// </summary>
        public long FileSize
        {
            get
            {
                return _file_length;
            }
            set
            {
                this.State = EntityState.Modified;
                _file_length = value;
            }
        }

        /// <summary>
        /// ID короткой ссылки
        /// </summary>
        public string ShotLinkID
        {
            get
            {
                return _short_link_id;
            }
            set
            {
                if (value == null) throw new ArgumentNullException();
                this.State = EntityState.Modified;
                _short_link_id = value;
            }
        }

        /// <summary>
        /// Имя файла
        /// </summary>
        public string OriginalFileName
        {
            get
            {
                return _original_file_name;
            }
            set
            {
                if (value == null) throw new ArgumentNullException();
                this.State = EntityState.Modified;
                _original_file_name = value;
            }
        }

        /// <summary>
        /// Путь к файлу на сервере относительно каталога размещения (Storage Dir)
        /// </summary>
        public string ServerSideFileName
        {
            get
            {
                return _server_side_file_name;
            }
            set
            {
                if (value == null) throw new ArgumentNullException();
                this.State = EntityState.Modified;
                _server_side_file_name = value;
            }
        }

        #region WeCannotUseThisHere!!! But it is already written
        /// <summary>
        /// Генерирует новый путь к файлу
        /// </summary>
        /// <returns>Путь к файлу на сервере</returns>
        public string MakeFullServersidePath()
        {
            StringBuilder tmp = new StringBuilder(Path.Combine(StorageDir, _server_side_file_name));
            StringBuilder underline_chars = new StringBuilder(new string('_', 2));

            while (tmp.ToString().IndexOf(underline_chars.ToString()) != -1 && underline_chars.Length <= FailConstant)
            {
                underline_chars.Append('_');
            }

            if (underline_chars.Length > FailConstant)
                return null;    // Don't know, who will upload such file

            int counter = 0;
            if (File.Exists(tmp.ToString()))
            {
                tmp.Append(_get_AntiCollider(underline_chars.ToString(), counter++));
            }

            while (File.Exists(tmp.ToString()) && counter <= (FailConstant * 100))
            {
                tmp.Replace(_get_AntiCollider(underline_chars.ToString(), counter), _get_AntiCollider(underline_chars.ToString(), ++counter));
            }
            if (counter > FailConstant)
                return null;

            return tmp.ToString();
        }

        private string _get_AntiCollider(string underline_chars, int counter)
        {
            return string.Format("{0}{1}", underline_chars, counter);
        }
        #endregion

        private void Init(int owner_id, string original_file_name, string serverside_file_name, string short_link_id, long file_size, bool shared = true)
        {
            this._owner_id = owner_id;
            this.OriginalFileName = original_file_name;
            this.ServerSideFileName = serverside_file_name;
            this.ShotLinkID = short_link_id;
            this.FileSize = file_size;
        }

        /// <summary>
        /// Конструктор новых хранимых файлов
        /// </summary>
        /// <param name="owner_id">ID владельца файла</param>
        /// <param name="original_file_name">Оригинальное имя файла</param>
        /// <param name="serverside_file_name">Серверное имя файла</param>
        /// <param name="short_link_id">Строка короткой ссылки</param>
        /// <param name="file_size">Размер файла в байтах</param>
        public HostedFile(int owner_id, string original_file_name, string serverside_file_name, string short_link_id, long file_size)
            : base()
        {
            Init(owner_id, original_file_name, serverside_file_name, short_link_id, file_size);
        }

        /// <summary>
        /// Конструктор для загруженных из базы данных файлов
        /// </summary>
        /// <param name="ID">ID из базы данных</param>
        /// <param name="owner_id">ID владельца файла</param>
        /// <param name="original_file_name">Оригинальное имя файла</param>
        /// <param name="serverside_file_name">Серверное имя файла</param>
        /// <param name="short_link_id">Строка короткой ссылки</param>
        /// <param name="file_size">Размер файла в байтах</param>
        public HostedFile(int ID, int owner_id, string original_file_name, string serverside_file_name, string short_link_id, long file_size, bool shared = true)
            : base(ID)
        {
            Init(owner_id, original_file_name, serverside_file_name, short_link_id, file_size, shared);
            this.State = EntityState.Unchanged;
        }


        /// <summary>
        /// Конструктор для файлов с другим статусом
        /// </summary>
        /// <param name="ID">ID из базы данных</param>
        /// <param name="state">Статус записи в базе данных</param>
        /// <param name="owner_id">ID владельца файла</param>
        /// <param name="original_file_name">Оригинальное имя файла</param>
        /// <param name="serverside_file_name">Серверное имя файла</param>
        /// <param name="short_link_id">Строка короткой ссылки</param>
        /// <param name="file_size">Размер файла в байтах</param>
        public HostedFile(int ID, EntityState state, int owner_id, string original_file_name, string serverside_file_name, string short_link_id, long file_size)
            : base(ID)
        {
            Init(owner_id, original_file_name, serverside_file_name, short_link_id, file_size);
            this.State = state;
        }

        public HostedFile(int ID)
            :base(ID)
        {
        }
    }
}
